#pragma once
#include<iostream>
#include<unordered_map>
#include"Connection.hpp"
#include"Socket.hpp"
#include"Epoller.hpp"

const int maxevents=1024;
const int TIMEOUT=-1;
using namespace Net_Work;
class TcpServer;



class TcpServer
{
public:
    TcpServer():_isrunning(false),_timeout(TIMEOUT)
    {
        _epoller.InitEpoller();
    }
    bool ExistsConnection(int sockfd)
    {
        auto it=_connections.find(sockfd);
        if(it==_connections.end())
        {
            return false;
        }
        return true;
    }
    void AddConnection(Connection* conn)
    {
        if(!conn)return;
        if(ExistsConnection(conn->GetFd()))
        {
            lg.LogMessage(Warning,"find connection...%s : %d\n",strerror(errno),errno);
            return;
        }
        _connections.insert(std::make_pair(conn->GetFd(),conn));
        lg.LogMessage(Info,"insert connection success...\n");
        _epoller.Add(conn->GetFd(),conn->GetEvent());
    }
    void EnableRecvSend(int sockfd,bool recver,bool sender)
    {
        if(!ExistsConnection(sockfd))
        {
            return;
        }
        uint32_t event=(recver?EPOLLIN:0)|(sender?EPOLLIN:0)|EPOLLET;
        _connections[sockfd]->SetEvent(event);
        _epoller.MOD(sockfd,event);
    }
    void LoopOnce(int timeout)
    {
        int n=_epoller.Wait(events, maxevents, timeout);
        for (int i = 0; i < n; i++)
        {
            int fd = events[i].data.fd;
            uint32_t event = events[i].events;
            if (event & EPOLLERR)
                event |= (EPOLLIN | EPOLLOUT);
            if (event & EPOLLHUP)
                event |= (EPOLLIN | EPOLLOUT);
            if ((event & EPOLLIN) && ExistsConnection(fd))
            {
                if (_connections[fd]->_recver)
                {
                    _connections[fd]->_recver(_connections[fd]);
                }
            }
            if ((event & EPOLLOUT) && ExistsConnection(fd))
            {
                if (_connections[fd]->_sender)
                {
                    _connections[fd]->_sender(_connections[fd]);
                }
            }
        }
    }
    void RemoveConnection(int sockfd)
    {
        if(!ExistsConnection(sockfd))
        {
            return;
        }
        _connections[sockfd]->SetEvent(0);
        _epoller.DelEvent(sockfd);
        _connections.erase(sockfd);
    }
    void Dispatcher()
    {
        _isrunning=true;
        while(_isrunning)
        {
            _epoller.PrintList();
            LoopOnce(_timeout);
        }
        _isrunning=false;
    }
    ~TcpServer(){}
private:
    Epoller _epoller;
    std::unordered_map<int,Connection*> _connections;
    bool _isrunning;
    struct epoll_event events[maxevents];
    int _timeout;
};